package org.dtrd.modules.record.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.CheckUtil;
import org.dtrd.common.util.DateUtils;
import org.dtrd.common.util.ObjectWrapperUtil;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.*;
import org.dtrd.modules.achievement.entity.bean.SignInAction;
import org.dtrd.modules.achievement.entity.po.DtrdEntRdSigninRecord;
import org.dtrd.modules.achievement.service.IDtrdEntRdSigninRecordService;
import org.dtrd.modules.record.entity.bean.*;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninSugarValue;
import org.dtrd.modules.record.entity.po.DtrdViewRlCheckinRecord;
import org.dtrd.modules.record.mapper.DtrdViewRlCheckinRecordMapper;
import org.dtrd.modules.record.service.*;
import org.dtrd.modules.util.SigninUtil;
import org.dtrd.common.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author 萧
 * @date 2021-12-05 09:30:04
 **/
@Service
@DS("multi-datasource1")
@Slf4j
public class DtrdViewRlCheckinRecordServiceImpl extends ServiceImpl<DtrdViewRlCheckinRecordMapper, DtrdViewRlCheckinRecord> implements IDtrdViewRlCheckinRecordService {

    @Autowired
    private DtrdEntRdUplowRecordServiceImpl uplowRecordService;

    @Autowired
    private ISugarRecordService sugarRecordService;

    @Autowired
    private IDtrdViewRlDailyGroupBloodPressureService bloodPressureViewService;

    @Autowired
    private IHeightWeightRecordService heightWeightRecordService;

    @Autowired
    private IKetoneRecordService ketoneRecordService;

    @Autowired
    private IWaistlineRecordService waistlineRecordService;

    @Autowired
    private IDtrdEntRdSigninSuggestService suggestService;
    @Autowired
    private IDtrdEntRdSigninRecordService signinRecordService;

    @Override
    public List<DailyGroupCheckinRecord> selectCheckinRecords(Integer patientId, String startTime, String endTime) {
//        return getFormatCheckinRecords(patientId, startTime, endTime, true, false);
        return getFormatCheckinRecordsV2(patientId, startTime, endTime, true, true);
    }

    @Override
    public List<DailyGroupCheckinRecord> getCheckinRecords(Integer patientId, String startTime, String endTime, boolean isDateDesc) {
//        return getFormatCheckinRecords(patientId, startTime, endTime, false, isDateDesc);
        return getFormatCheckinRecordsV2(patientId, startTime, endTime, false, isDateDesc);
    }

    /**
     * @param patientId
     * @param startTime
     * @param endTime
     * @param insertWeekAndMonth
     * @param isDateAsc
     * @return
     * @deprecated user V2
     */
    private List<DailyGroupCheckinRecord> getFormatCheckinRecords(Integer patientId, String startTime, String endTime, boolean insertWeekAndMonth, boolean isDateAsc) {
        List<DtrdViewRlCheckinRecord> list = baseMapper.selectCheckinRecords(patientId, startTime, endTime, null, isDateAsc ? "asc" : "desc");
        Map<String, List<DtrdViewRlCheckinRecord>> tmpMap = new HashMap<>(5);
        List<DtrdViewRlCheckinRecord> tmpList;
        String date;
        for (DtrdViewRlCheckinRecord po : list) {
            date = DateUtils.formatDate(po.getRecordDate(), DateUtils.short_date_sdf_wz.get().toPattern());
            tmpList = tmpMap.get(po.getPatientId() + "-" + date);
            if (tmpList == null) {
                tmpList = new ArrayList<>(10);
            }
            tmpList.add(po);
            tmpMap.put(po.getPatientId() + "-" + date, tmpList);
        }
        List<DailyGroupCheckinRecord> dataList = null;
        if (tmpMap != null) {
            ValueUplowBean sugarValueUpLowRecord = uplowRecordService.getSugarValueUpLowRecord(-1, patientId);
            // 空则用初始值进行判断
            if (sugarValueUpLowRecord == null) {
                sugarValueUpLowRecord = new ValueUplowBean();
            }
            dataList = new ArrayList<>(tmpMap.size());
            DailyGroupCheckinRecord record;
            for (Map.Entry<String, List<DtrdViewRlCheckinRecord>> entry : tmpMap.entrySet()) {
                String key = entry.getKey();
                List<DtrdViewRlCheckinRecord> recordList = entry.getValue();
                record = new DailyGroupCheckinRecord();
                record.setRecordDate(key.split("-")[1]);
                if (CheckUtil.isNotEmpty(recordList)) {
                    for (DtrdViewRlCheckinRecord po : recordList) {
                        record.setSourceDate(po.getRecordDate());
                        record.setWeekStart(DateUtil.beginOfWeek(po.getRecordDate()).toDateStr());
                        record.setMonthStart(DateUtil.beginOfMonth(po.getRecordDate()).toDateStr());
                        RecordType recordType = RecordType.valueOf(po.getRecordType());
                        switch (recordType) {
                            case SUGAR:
                                handleSugarRecord(record, po.getSubType(), StringUtil.StrTrimFloat(po.getRecordValue()), sugarValueUpLowRecord);
                                break;
                            case DIET: {
                                if (po.getSubType() == Constant.FoodRecordType.BREAKFAST.getType()) {
                                    record.setK9(po.getRecordPhoto());
                                    record.setK9PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK9Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.FoodRecordType.LUNCH.getType()) {
                                    record.setK10(po.getRecordPhoto());
                                    record.setK10PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK10Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.FoodRecordType.DINNER.getType()) {
                                    record.setK11(po.getRecordPhoto());
                                    record.setK11PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK11Describe(po.getRecordValue());
                                }
                            }
                            break;
                            case SPORT:
                                record.setK12(po.getRecordPhoto());
                                record.setK12PlanState(SigninItemPlanStatus.NORMAL.getType());
                                break;
                            case MEDICAL: {
                                if (po.getSubType() == Constant.MedicalRecordType.MORNING.getType()) {
                                    record.setK13(po.getRecordPhoto());
                                    record.setK13PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK13Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.MedicalRecordType.NOON.getType()) {
                                    record.setK14(po.getRecordPhoto());
                                    record.setK14PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK14Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.MedicalRecordType.EVENING.getType()) {
                                    record.setK15(po.getRecordPhoto());
                                    record.setK15PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK15Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.MedicalRecordType.SLEEP.getType()) {
                                    record.setK16(po.getRecordPhoto());
                                    record.setK16PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK16Describe(po.getRecordValue());
                                }
                            }
                            break;
                            case INSULIN: {
                                if (po.getSubType() == Constant.InsulinRecordType.MORNING.getType()) {
                                    record.setK17(po.getRecordPhoto());
                                    record.setK17PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK17Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.MedicalRecordType.NOON.getType()) {
                                    record.setK18(po.getRecordPhoto());
                                    record.setK18PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK18Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.MedicalRecordType.EVENING.getType()) {
                                    record.setK19(po.getRecordPhoto());
                                    record.setK19PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK19Describe(po.getRecordValue());
                                } else if (po.getSubType() == Constant.MedicalRecordType.SLEEP.getType()) {
                                    record.setK20(po.getRecordPhoto());
                                    record.setK20PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK20Describe(po.getRecordValue());
                                }
                            }
                            break;
                            case SLEEP:
                                Constant.SleepStatus status = Constant.SleepStatus.valueOf(StringUtil.StrTrimInt(po.getRecordValue()));
                                if (status != null) {
                                    record.setK21(status.getSleepStatusDesc());
                                    record.setK21PlanState(SigninItemPlanStatus.NORMAL.getType());
                                }
                                break;
                            case WEIGHT:
                                record.setK22(po.getRecordValue());
                                record.setK22PlanState(SigninItemPlanStatus.NORMAL.getType());
                                break;
                            case KETONE:
                                record.setK23(po.getRecordPhoto());
                                record.setK23Describe(po.getRecordValue());
                                record.setK23PlanState(SigninItemPlanStatus.NORMAL.getType());
                                break;
                            case WAIST:
                                record.setK24(po.getRecordValue());
                                record.setK24PlanState(SigninItemPlanStatus.NORMAL.getType());
                                break;
                            case BLOOD_PRESSURE: {
                                if (po.getSubType() == Constant.BloodPressureRecordType.MORNING.getType()) {
                                    record.setK25(SigninUtil.floatToInt(po.getRecordValue()));
                                    record.setK26(SigninUtil.floatToInt(po.getRecordValue2()));
                                    record.setK27(SigninUtil.floatToInt(po.getRecordValue3()));
                                    record.setK25PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK26PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK27PlanState(SigninItemPlanStatus.NORMAL.getType());
                                } else if (po.getSubType() == Constant.BloodPressureRecordType.EVENING.getType()) {
                                    record.setK28(SigninUtil.floatToInt(po.getRecordValue()));
                                    record.setK29(SigninUtil.floatToInt(po.getRecordValue2()));
                                    record.setK30(SigninUtil.floatToInt(po.getRecordValue3()));
                                    record.setK28PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK29PlanState(SigninItemPlanStatus.NORMAL.getType());
                                    record.setK30PlanState(SigninItemPlanStatus.NORMAL.getType());
                                }
                            }
                            break;
                            default:
                                break;
                        }
                    }
                }
                dataList.add(record);
            }
            dataList.sort((o1, o2) -> o2.getRecordDate().compareTo(o1.getRecordDate()));
            if (insertWeekAndMonth) {
                DailyGroupCheckinRecord checkinRecord, preCheckinRecord, week, month;
                int weekIndex = 1;
                // 依次遍历找到插入周汇总、月汇总的位置
                for (int i = 0; i < dataList.size(); i++) {
                    preCheckinRecord = i >= 1 ? dataList.get(i - 1) : null;
                    if (preCheckinRecord != null && preCheckinRecord.getRecordStat() == Constant.SigninRecordStat.DateStat.getType()) {
                        checkinRecord = dataList.get(i);
                        // 与前一项比较是否同一周，是否同一月
                        if (!Objects.equals(checkinRecord.getMonthStart(), preCheckinRecord.getMonthStart())) {
                            // 跨月，生成上一月汇总
                            month = generateMonthStat(patientId, (DateUtil.date(preCheckinRecord.getSourceDate()).getField(Calendar.MONTH) + 1) + "月汇总", preCheckinRecord.getMonthStart(), DateUtil.endOfMonth(preCheckinRecord.getSourceDate()).toDateStr());
                            int[] checkinCounts = findImageCheckinCount(dataList, i, SigninRecordStat.MonthStat.getType());
                            if (month.getK9() == null) {
                                month.setK9(checkinCounts[0] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK12() == null) {
                                month.setK12(checkinCounts[1] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK13() == null) {
                                month.setK13(checkinCounts[2] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK17Describe() == null) {
                                month.setK17Describe(checkinCounts[3] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK21() == null) {
                                month.setK21(checkinCounts[4] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            dataList.add(i, month);
                            // 重置周索引
                            weekIndex = 1;
                        }
                        if (!Objects.equals(checkinRecord.getWeekStart(), preCheckinRecord.getWeekStart())) {
                            // 跨周 生成上一周汇总
                            week = generateWeekStat(patientId, "第" + weekIndex + "周汇总", preCheckinRecord.getWeekStart(), DateUtil.endOfWeek(preCheckinRecord.getSourceDate()).toDateStr());
                            int[] checkinCounts = findImageCheckinCount(dataList, i, SigninRecordStat.WeekStat.getType());
                            dataList.add(i, week);
                            weekIndex += 1;
                        }
                    }
                }
            }
        }
        return dataList;
    }

    private List<DailyGroupCheckinRecord> getFormatCheckinRecordsV2(Integer patientId, String startTime, String endTime, boolean insertWeekAndMonth, boolean isDateDesc) {
        List<DtrdEntRdSigninRecord> signinRecords = signinRecordService.getSigninRecords(patientId, startTime, endTime, isDateDesc);
        List<DailyGroupCheckinRecord> dataList = null;
        if (CollectionUtil.isNotEmpty(signinRecords)) {
            dataList = new ArrayList<>(signinRecords.size());
            signinRecords.stream().filter(dr -> StrUtil.isNotBlank(dr.getSighInJson()))
                    .map(dr -> {
                        List<SignInAction> actionList = JSONObject.parseArray(dr.getSighInJson(), SignInAction.class);
                        DailyGroupCheckinRecord record = new DailyGroupCheckinRecord();
                        record.setRecordDate(DateUtils.formatDate(dr.getRecordDate()));
                        record.setSourceDate(dr.getRecordDate());
                        record.setWeekStart(DateUtil.beginOfWeek(dr.getRecordDate()).toDateStr());
                        record.setMonthStart(DateUtil.beginOfMonth(dr.getRecordDate()).toDateStr());
                        record.setPatientId(dr.getPatientId());
                        ValueUplowBean sugarValueUpLowRecord = uplowRecordService.getSugarValueUpLowRecord(-1, patientId);
                        actionList.stream()
                                // 过滤未配置项
                                .filter(action -> !(StringUtils.isEmpty(action.getStarttime()) || StringUtils.isEmpty(action.getEndtime())))
                                .peek(po -> {
                                    // 处理打卡状态- 待打卡、漏打卡、已打卡
                                    Integer isDone = Optional.ofNullable(po.getIsDone()).orElse(RecordState.TO_BE_RECORD.getState());
                                    Integer signinItemPlanStatus = SigninItemPlanStatus.valueOfRecordState(isDone);
                                    if (signinItemPlanStatus == SigninItemPlanStatus.NOPLAN.getType()) {
                                        po.setSigninItemValue(SigninItemPlanStatus.NOPLAN.getStatus());
                                    }
                                    po.setSigninItemPlanStatus(signinItemPlanStatus);
                                })
                                .forEach(po -> {
                                    RecordType recordType = RecordType.valueOf(po.getRecordType());
                                    String defaultValue = po.getSigninItemValue();
                                    switch (recordType) {
                                        case SUGAR:
                                            handleSugarRecordV2(record, po, sugarValueUpLowRecord);
                                            break;
                                        case DIET: {
                                            if (po.getSubType() == FoodRecordType.BREAKFAST.getType()) {
                                                record.setK9PlanState(po.getSigninItemPlanStatus());
                                                record.setK9(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK9Describe(po.getRecordValue());
                                            } else if (po.getSubType() == FoodRecordType.LUNCH.getType()) {
                                                record.setK10(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK10PlanState(po.getSigninItemPlanStatus());
                                                record.setK10Describe(po.getRecordValue());
                                            } else if (po.getSubType() == FoodRecordType.DINNER.getType()) {
                                                record.setK11(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK11PlanState(po.getSigninItemPlanStatus());
                                                record.setK11Describe(po.getRecordValue());
                                            }
                                        }
                                        break;
                                        case SPORT:
                                            record.setK12(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                            record.setK12PlanState(po.getSigninItemPlanStatus());
                                            break;
                                        case MEDICAL: {
                                            if (po.getSubType() == MedicalRecordType.MORNING.getType()) {
                                                record.setK13(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK13PlanState(po.getSigninItemPlanStatus());
                                                record.setK13Describe(po.getRecordValue());
                                            } else if (po.getSubType() == MedicalRecordType.NOON.getType()) {
                                                record.setK14(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK14PlanState(po.getSigninItemPlanStatus());
                                                record.setK14Describe(po.getRecordValue());
                                            } else if (po.getSubType() == MedicalRecordType.EVENING.getType()) {
                                                record.setK15(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK15PlanState(po.getSigninItemPlanStatus());
                                                record.setK15Describe(po.getRecordValue());
                                            } else if (po.getSubType() == MedicalRecordType.SLEEP.getType()) {
                                                record.setK16(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK16PlanState(po.getSigninItemPlanStatus());
                                                record.setK16Describe(po.getRecordValue());
                                            }
                                        }
                                        break;
                                        case INSULIN: {
                                            if (po.getSubType() == InsulinRecordType.MORNING.getType()) {
                                                record.setK17(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK17PlanState(po.getSigninItemPlanStatus());
                                                record.setK17Describe(po.getRecordValue());
                                            } else if (po.getSubType() == MedicalRecordType.NOON.getType()) {
                                                record.setK18(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK18PlanState(po.getSigninItemPlanStatus());
                                                record.setK18Describe(po.getRecordValue());
                                            } else if (po.getSubType() == MedicalRecordType.EVENING.getType()) {
                                                record.setK19(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK19PlanState(po.getSigninItemPlanStatus());
                                                record.setK19Describe(po.getRecordValue());
                                            } else if (po.getSubType() == MedicalRecordType.SLEEP.getType()) {
                                                record.setK20(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK20PlanState(po.getSigninItemPlanStatus());
                                                record.setK20Describe(po.getRecordValue());
                                            }
                                        }
                                        break;
                                        case SLEEP:
                                            SleepStatus status = SleepStatus.valueOf(StringUtil.StrTrimInt(po.getRecordValue()));
                                            if (status != null) {
                                                record.setK21(status.getSleepStatusDesc());
                                            }
                                            record.setK21PlanState(po.getSigninItemPlanStatus());
                                            break;
                                        case WEIGHT:
                                            record.setK22(po.getRecordValue());
                                            record.setK22PlanState(po.getSigninItemPlanStatus());
                                            break;
                                        case KETONE:
                                            record.setK23(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                            record.setK23Describe(po.getRecordValue());
                                            record.setK23PlanState(po.getSigninItemPlanStatus());
                                            break;
                                        case WAIST:
                                            record.setK24(po.getRecordValue());
                                            record.setK24PlanState(po.getSigninItemPlanStatus());
                                            break;
                                        case BLOOD_PRESSURE: {
                                            if (po.getSubType() == BloodPressureRecordType.MORNING.getType()) {
                                                record.setK25(SigninUtil.floatToInt(po.getRecordValue()));
                                                record.setK26(SigninUtil.floatToInt(po.getRecordValue2()));
                                                record.setK27(SigninUtil.floatToInt(po.getRecordValue3()));
                                                record.setK25PlanState(po.getSigninItemPlanStatus());
                                                record.setK26PlanState(po.getSigninItemPlanStatus());
                                                record.setK27PlanState(po.getSigninItemPlanStatus());
                                            } else if (po.getSubType() == BloodPressureRecordType.EVENING.getType()) {
                                                record.setK28(SigninUtil.floatToInt(po.getRecordValue()));
                                                record.setK29(SigninUtil.floatToInt(po.getRecordValue2()));
                                                record.setK30(SigninUtil.floatToInt(po.getRecordValue3()));
                                                record.setK28PlanState(po.getSigninItemPlanStatus());
                                                record.setK29PlanState(po.getSigninItemPlanStatus());
                                                record.setK30PlanState(po.getSigninItemPlanStatus());
                                            }
                                        }
                                        break;
                                        case NUTRIENT:
                                            if (po.getSubType() == NutrientRecordType.MORNING.getType()) {
                                                record.setK31(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK31PlanState(po.getSigninItemPlanStatus());
                                                record.setK31Describe(po.getRecordValue());
                                            } else if (po.getSubType() == NutrientRecordType.NOON.getType()) {
                                                record.setK32(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK32PlanState(po.getSigninItemPlanStatus());
                                                record.setK32Describe(po.getRecordValue());
                                            } else if (po.getSubType() == NutrientRecordType.EVENING.getType()) {
                                                record.setK33(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK33PlanState(po.getSigninItemPlanStatus());
                                                record.setK33Describe(po.getRecordValue());
                                            } else if (po.getSubType() == NutrientRecordType.SLEEP.getType()) {
                                                record.setK34(ObjectWrapperUtil.wrapper(po.getRecordPhoto(), defaultValue));
                                                record.setK34PlanState(po.getSigninItemPlanStatus());
                                                record.setK34Describe(po.getRecordValue());
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                });
                        return record;
                    }).forEach(dataList::add);
            log.info("DtrdViewRlCheckinRecordServiceImpl.getFormatCheckinRecordsV2.[patientId, startTime, endTime, insertWeekAndMonth, isDateDesc] " + insertWeekAndMonth + "; dataList.size()=" + dataList.size());
            if (insertWeekAndMonth) {
                DailyGroupCheckinRecord checkinRecord, preCheckinRecord, week, month;
                int weekIndex = 1;
                // 依次遍历找到插入周汇总、月汇总的位置
                for (int i = 0; i < dataList.size(); i++) {
                    preCheckinRecord = i >= 1 ? dataList.get(i - 1) : null;
                    if (preCheckinRecord != null && preCheckinRecord.getRecordStat() == Constant.SigninRecordStat.DateStat.getType()) {
                        checkinRecord = dataList.get(i);
                        // 与前一项比较是否同一周，是否同一月
                        if (!Objects.equals(checkinRecord.getMonthStart(), preCheckinRecord.getMonthStart())) {
                            // 跨月，生成上一月汇总
                            month = generateMonthStat(patientId, (DateUtil.date(preCheckinRecord.getSourceDate()).getField(Calendar.MONTH) + 1) + "月汇总", preCheckinRecord.getMonthStart(), DateUtil.endOfMonth(preCheckinRecord.getSourceDate()).toDateStr());
                            int[] checkinCounts = findImageCheckinCount(dataList, i, SigninRecordStat.MonthStat.getType());
                            if (month.getK9() == null) {
                                month.setK9(checkinCounts[0] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK12() == null) {
                                month.setK12(checkinCounts[1] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK13() == null) {
                                month.setK13(checkinCounts[2] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK17Describe() == null) {
                                month.setK17Describe(checkinCounts[3] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            if (month.getK21() == null) {
                                month.setK21(checkinCounts[4] == 0 ? "" : ("打卡" + checkinCounts[0]));
                            }
                            dataList.add(i, month);
                            // 重置周索引
                            weekIndex = 1;
                        }
                        if (!Objects.equals(checkinRecord.getWeekStart(), preCheckinRecord.getWeekStart())) {
                            // 跨周 生成上一周汇总
                            week = generateWeekStat(patientId, "第" + weekIndex + "周汇总", preCheckinRecord.getWeekStart(), DateUtil.endOfWeek(preCheckinRecord.getSourceDate()).toDateStr());
                            dataList.add(i, week);
                            weekIndex += 1;
                        }
                    }
                }
            }
            log.info("DtrdViewRlCheckinRecordServiceImpl.getFormatCheckinRecordsV2.[patientId, startTime, endTime, insertWeekAndMonth, isDateDesc] ater week " + "; dataList.size()=" + dataList.size());
        }
        return dataList;
    }

    /**
     * @param dataList
     * @param reverseIndex
     * @param endStatType
     * @return
     */
    private int[] findImageCheckinCount(List<DailyGroupCheckinRecord> dataList, int reverseIndex, int endStatType) {
        int k9 = 0, k12 = 0, k13 = 0, k17 = 0, k21 = 0;
        for (int i = reverseIndex; i >= 0; i--) {
            DailyGroupCheckinRecord record = dataList.get(i);
            if (record.getRecordStat() == Constant.SigninRecordStat.DateStat.getType()) {
                if (record.getK9() != null) {
                    k9++;
                }
                if (record.getK12() != null) {
                    k12++;
                }
                if (record.getK13() != null) {
                    k13++;
                }
                if (record.getK17() != null) {
                    k17++;
                }
                if (record.getK21() != null) {
                    k21++;
                }
            } else if (record.getRecordStat() == endStatType) {
                break;
            }
        }
        return new int[]{k9, k12, k13, k17, k21};
    }

    private DailyGroupCheckinRecord generateMonthStat(Integer patientId, String recordDateName, String monthStart, String endOfMonth) {
        return generatePeriodStat(patientId, Constant.SigninRecordStat.MonthStat.getType(), recordDateName
                , monthStart, endOfMonth);
    }

    private DailyGroupCheckinRecord generateWeekStat(Integer patientId, String recordDateName, String weekStart, String endOfWeek) {
        return generatePeriodStat(patientId, Constant.SigninRecordStat.WeekStat.getType(), recordDateName, weekStart, endOfWeek);
    }

    private DailyGroupCheckinRecord generatePeriodStat(Integer patientId, int statType, String recordDateName, String startDate, String endDate) {
        DailyGroupCheckinRecord record = new DailyGroupCheckinRecord();
        record.setRecordStat(statType);
        record.setRecordDate(recordDateName);
        // 计算血糖平均值
        ValueUplowBean sugarValueUpLowRecord = uplowRecordService.getSugarValueUpLowRecord(-1, patientId);
        List<AvgRecordBean> avgSugarRecordList = sugarRecordService.getAvgSugarRecord(patientId, startDate, endDate);
        avgSugarRecordList.forEach(avgRecord -> {
            handleSugarRecord(record, avgRecord.getSubType(), avgRecord.getAvgValue(), sugarValueUpLowRecord);
        });

        // 计算体重
        Float avgWeight = heightWeightRecordService.getAvgWeight(patientId, startDate, endDate);
        if (avgWeight != null) {
            record.setK22(avgWeight + "");
        }
        // 计算尿酮
        AvgRecordBean ketongValue = ketoneRecordService.getAvgValue(patientId, startDate, endDate);
        if (ketongValue != null && ketongValue.getAvgValue() != null) {
            record.setK23(String.valueOf(ketongValue.getAvgValue()));
        }
        // 计算腰围平均值
        AvgRecordBean waistRecord = waistlineRecordService.getAvgValue(patientId, startDate, endDate);
        if (waistRecord != null && waistRecord.getAvgValue() != null) {
            record.setK24(String.valueOf(waistRecord.getAvgValue()));
        }
        // 计算血压平均值
        AvgBloodPressure bloodPressure = bloodPressureViewService.getAvgBloodPresssure(patientId, startDate, endDate);
        if (bloodPressure != null) {
            record.setK25(bloodPressure.getBloodPressureHighPressure());
            record.setK26(bloodPressure.getBloodPressureLowVoltage());
            record.setK27(bloodPressure.getBloodPressureHeartRate());
            record.setK28(bloodPressure.getNightHighPressure());
            record.setK29(bloodPressure.getNightLowVoltage());
            record.setK30(bloodPressure.getNightHeartRate());
        }

        // 周/月汇总 饮食、运动、用药、胰岛素、作息五项状态数据 取最近一条建议
        List<SigninSuggestBean> suggestBeanList = suggestService.getSuggestByPatientIdAndTypes(patientId, SuggestType.MEDICAL.getType(),
                SuggestType.DIET.getType(),
                SuggestType.INSULIN.getType(),
                SuggestType.SLEEP.getType(),
                SuggestType.SPORT.getType());
        if (CollectionUtil.isNotEmpty(suggestBeanList)) {
            suggestBeanList.forEach(sugget -> {
                Constant.SuggestType suggestType = Constant.SuggestType.valueOf(sugget.getSigninType());
                switch (suggestType) {
                    case DIET:
                        record.setK9(sugget.getSuggestContent());
                        break;
                    case SPORT:
                        record.setK12(sugget.getSuggestContent());
                        break;
                    case MEDICAL:
                        record.setK13(sugget.getSuggestContent());
                        break;
                    case INSULIN:
                        record.setK17Describe(sugget.getSuggestContent());
                        break;
                    case SLEEP:
                        record.setK21(sugget.getSuggestContent());
                        break;
                    default:
                        break;
                }
            });
        } else {
            record.setK9("");
            record.setK12("");
            record.setK13("");
            record.setK17("");
            record.setK21("");
        }
        return record;
    }

    /**
     * 将血糖数据转换至打卡记录，并判断记录类型
     *
     * @param record
     * @param subType
     * @param recordValue
     * @param sugarValueUpLowRecord
     */
    private void handleSugarRecord(DailyGroupCheckinRecord record, Integer subType, Float recordValue, ValueUplowBean sugarValueUpLowRecord) {
        if (sugarValueUpLowRecord == null) {
            sugarValueUpLowRecord = new ValueUplowBean();
        }
        String recordValueStr = ObjectWrapperUtil.wrapper(recordValue, null, String::valueOf);
        Integer state = null;
        if (recordValue != null && Optional.ofNullable(record.getRecordStat()).orElse(0) == 0) {
            state = judgeRecordStatus(recordValue,
                    sugarValueUpLowRecord.getLowerValueLimosis(),
                    sugarValueUpLowRecord.getUpperValueLimosis());
        }
        if (subType == Constant.SugarRecordType.BEFOREBREAKFAST.getType()) {
            record.setK1(recordValueStr);
            record.setK1PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK1State(state);
        } else if (subType == Constant.SugarRecordType.AFTERBREAKFAST.getType()) {
            record.setK2(recordValueStr);
            record.setK2PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK2State(state);
        } else if (subType == Constant.SugarRecordType.BEFORELUNCH.getType()) {
            record.setK3(recordValueStr);
            record.setK3PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK3State(state);
        } else if (subType == Constant.SugarRecordType.AFTERLUNCH.getType()) {
            record.setK4(recordValueStr);
            record.setK4PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK4State(state);
        } else if (subType == Constant.SugarRecordType.BEFOREDINNER.getType()) {
            record.setK5(recordValueStr);
            record.setK5PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK5State(state);
        } else if (subType == Constant.SugarRecordType.AFTERDINNER.getType()) {
            record.setK6(recordValueStr);
            record.setK6PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK6State(state);
        } else if (subType == Constant.SugarRecordType.EARLYMORNING.getType()) {
            record.setK7(recordValueStr);
            record.setK7PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK7State(state);
        } else if (subType == Constant.SugarRecordType.BEFORESLEEP.getType()) {
            record.setK8(recordValueStr);
            record.setK8PlanState(SigninItemPlanStatus.NORMAL.getType());
            record.setK8State(state);
        }
    }

    private void handleSugarRecordV2(DailyGroupCheckinRecord record, SignInAction po, ValueUplowBean sugarValueUpLowRecord) {
        if (sugarValueUpLowRecord == null) {
            sugarValueUpLowRecord = new ValueUplowBean();
        }
        Integer subType = po.getSubType();
        String recordValue = po.getRecordValue();
        Integer state = null;
        if (recordValue != null && Optional.ofNullable(record.getRecordStat()).orElse(0) == 0) {
            state = judgeRecordStatus(StringUtil.StrTrimFloat(recordValue),
                    sugarValueUpLowRecord.getLowerValueLimosis(),
                    sugarValueUpLowRecord.getUpperValueLimosis());
        }
        recordValue = ObjectWrapperUtil.wrapper(recordValue, po.getSigninItemValue());
        if (subType == Constant.SugarRecordType.BEFOREBREAKFAST.getType()) {
            record.setK1(recordValue);
            record.setK1PlanState(po.getSigninItemPlanStatus());
            record.setK1State(state);
        } else if (subType == Constant.SugarRecordType.AFTERBREAKFAST.getType()) {
            record.setK2(recordValue);
            record.setK2PlanState(po.getSigninItemPlanStatus());
            record.setK2State(state);
        } else if (subType == Constant.SugarRecordType.BEFORELUNCH.getType()) {
            record.setK3(recordValue);
            record.setK3PlanState(po.getSigninItemPlanStatus());
            record.setK3State(state);
        } else if (subType == Constant.SugarRecordType.AFTERLUNCH.getType()) {
            record.setK4(recordValue);
            record.setK4PlanState(po.getSigninItemPlanStatus());
            record.setK4State(state);
        } else if (subType == Constant.SugarRecordType.BEFOREDINNER.getType()) {
            record.setK5(recordValue);
            record.setK5PlanState(po.getSigninItemPlanStatus());
            record.setK5State(state);
        } else if (subType == Constant.SugarRecordType.AFTERDINNER.getType()) {
            record.setK6(recordValue);
            record.setK6PlanState(po.getSigninItemPlanStatus());
            record.setK6State(state);
        } else if (subType == Constant.SugarRecordType.EARLYMORNING.getType()) {
            record.setK7(recordValue);
            record.setK7PlanState(po.getSigninItemPlanStatus());
            record.setK7State(state);
        } else if (subType == Constant.SugarRecordType.BEFORESLEEP.getType()) {
            record.setK8(recordValue);
            record.setK8PlanState(po.getSigninItemPlanStatus());
            record.setK8State(state);
        }
    }

    private Integer judgeRecordStatus(Float value, Float limitLow, Float limitUp) {
        if (value != null && limitLow != null && limitUp != null) {
            if (value < limitLow) {
                return Constant.RecordStatus.LOWER.getType();
            } else if (value > limitUp) {
                return Constant.RecordStatus.HIGHER.getType();
            }
        }
        return Constant.RecordStatus.NORMAL.getType();
    }

    @Override
    public List<DtrdViewRlCheckinRecord> selectCheckinRecordsByRecordTypes(Integer patientId, String startTime, String endTime, String recordTypes) {
        return baseMapper.selectCheckinRecords(patientId, startTime, endTime, recordTypes, "asc");
    }

    @Override
    public List<DtrdViewRlCheckinRecord> selectCheckinGroupRecordsByRecordTypes(Integer patientId, String startTime, String endTime, String recordTypes) {
        return baseMapper.selectCheckinGroupRecordsByRecordTypes(patientId, startTime, endTime, recordTypes, "asc");
    }

    @Override
    public List<DailySugarRecordBean> getDailySugarRecord(Integer patientId, String startDate, String endDate, Integer page, Integer pageSize) {
        List<DailySugarRecord> list = baseMapper.getDailySugarRecord(patientId, startDate, endDate, page, pageSize);
        if (CheckUtil.isNotEmpty(list)) {
            List<DailySugarRecordBean> dataList = new ArrayList<>(list.size());
            list.stream().map(record -> {
                DailySugarRecordBean item = new DailySugarRecordBean();
                item.setPatientId(record.getPatientId());
                item.setFormatDate(record.getFormatDate());
                item.setDate(record.getDate());
//                log.info("DtrdViewRlCheckinRecordServiceImpl.getDailySugarRecord.[patientId, startDate, endDate, page, pageSize] getValueStr=" + record.getValueStr() + ";");
                // 按照查询语句中拼接字符进行分割
                Arrays.stream(record.getValueStr().split(",")).map(
                        str -> str.split("_")
                ).forEach(array -> {
                    int type = StringUtil.StrTrimInt(array[0]);
                    Float value = StringUtil.StrTrimFloat(array[1]);
                    SugarValueBean sugarValue;

                    Integer photoDataId = StringUtil.StrTrimInt(array[4]);
                    if (photoDataId > 0) {
                        DtrdEntRdSigninSugarValue sugarRecord = sugarRecordService.getById(photoDataId);
                        sugarValue = new SugarValueBean(value, type, StringUtil.StrTrimInt(array[2]), sugarRecord == null ? null : sugarRecord.getRecordPhoto());
                    } else {
                        sugarValue = new SugarValueBean(value, type, StringUtil.StrTrimInt(array[2]), null);
                    }
                    sugarValue.setSugarValueType(StringUtil.StrTrimInt(array[5]));
                    sugarValue.setTime(array[3]);
                    Constant.SugarRecordType recordType = Constant.SugarRecordType.valueOf(type);
//                    log.info("DtrdViewRlCheckinRecordServiceImpl.getDailySugarRecord.[patientId, startDate, endDate, page, pageSize] type = " + type + ";recordType=" + recordType);
                    switch (recordType) {
                        case BEFOREBREAKFAST:
                            item.setBeforeBreakfast(value);
                            item.setBeforeBreakfastRecord(sugarValue);
                            item.setBeforeBreakfastStatus(sugarValue.getSugarValueType());
                            break;
                        case AFTERBREAKFAST:
                            item.setAfterBreakfast(value);
                            item.setAfterBreakfastRecord(sugarValue);
                            item.setAfterBreakfastStatus(sugarValue.getSugarValueType());
                            break;
                        case BEFORELUNCH:
                            item.setBeforeLunch(value);
                            item.setBeforeLunchRecord(sugarValue);
                            item.setBeforeLunchStatus(sugarValue.getSugarValueType());
                            break;
                        case AFTERLUNCH:
                            item.setAfterLunch(value);
                            item.setAfterLunchRecord(sugarValue);
                            item.setAfterLunchStatus(sugarValue.getSugarValueType());
                            break;
                        case BEFOREDINNER:
                            item.setBeforeDinner(value);
                            item.setBeforeDinnerRecord(sugarValue);
                            item.setBeforeDinnerStatus(sugarValue.getSugarValueType());
                            break;
                        case AFTERDINNER:
                            item.setAfterDinner(value);
                            item.setAfterDinnerRecord(sugarValue);
                            item.setAfterDinnerStatus(sugarValue.getSugarValueType());
                            break;
                        case BEFORESLEEP:
                            item.setBeforeSleep(value);
                            item.setBeforeSleepRecord(sugarValue);
                            item.setBeforeSleepStatus(sugarValue.getSugarValueType());
                            break;
                        case EARLYMORNING:
                            item.setEarlyMorning(value);
                            item.setEarlyMorningStatus(sugarValue.getSugarValueType());
                            break;
                        default:
                            item.setRandomTime(value);
                            item.setRandomTimeStatus(sugarValue.getSugarValueType());
                            break;
                    }
                });
                return item;
            }).forEach(dataList::add);
            return dataList;
        }
        return null;
    }


}
